package cn.admin.remoting.impl;

import cn.admin.remoting.ClientManager;
import cn.admin.remoting.IOEventListener;
import cn.admin.remoting.Remoting;
import cn.admin.remoting.util.ConnectionUrl;

import java.net.InetSocketAddress;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

class ReconnectManager {

    private final Hashtable<String, ScheduledFuture<?>> tasks = new Hashtable<>();

    synchronized boolean addReconnectTask(String appName,String targetUrl,
                                          InetSocketAddress localAddress,
                                          List<IOEventListener> listeners) {
        if (!ConnectionUrl.isAutoReconnect(targetUrl)) {
            return false;
        } else {
            String taskKey = ClientKeyUtil.singleClientKey(appName,targetUrl,localAddress);
            if (this.tasks.contains(taskKey)) {
                return false;
            } else {
                Reconnect task = new Reconnect(taskKey,listeners);
                ScheduledFuture<?> future =
                        DefaultClientManager.timer.scheduleWithFixedDelay(task,0L,
                                task.reconnectInterval, TimeUnit.MILLISECONDS);
                this.tasks.put(taskKey,future);
                return true;
            }
        }
    }

    void stopAllTasks() {
        synchronized (tasks) {
            for (Map.Entry<String,ScheduledFuture<?>> entry : tasks.entrySet()) {
                entry.getValue().cancel(true);
            }
        }
    }

    int taskSize() {
        return this.tasks.size();
    }

    private class Reconnect implements Runnable {

        private ClientManager.ClientFuture cf;
        private final String reconnectKey;
        private final List<IOEventListener> listeners;
        private final String appName;
        private final String targetUrl;
        private final InetSocketAddress localAddress;
        private final long reconnectInterval;

        Reconnect(String reconnectKey,List<IOEventListener> listeners) {
            if (reconnectKey == null) {
                throw new IllegalArgumentException();
            } else {
                this.reconnectKey = reconnectKey;
                this.listeners = listeners;
                Object temp[] = ClientKeyUtil.parseClientKey(reconnectKey);
                this.appName = (String)temp[0];
                this.targetUrl = (String)temp[1];
                this.localAddress = (InetSocketAddress) temp[2];
                ConnectionUrl url = ConnectionUrl.get(this.targetUrl);
                this.reconnectInterval = Long.valueOf(url.getProperty("_AUTORECONNECT_SLEEPTIME"));
            }
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            } else if (this == obj) {
                return true;
            } else if (!(obj instanceof Reconnect)) {
                return false;
            } else {
                Reconnect another = (Reconnect) obj;
                return another.reconnectKey.equals(this.reconnectKey);
            }
        }

        boolean isConnected() {
            return this.cf != null && this.cf.isConnected();
        }

        boolean isConnectDone() {
            return this.cf != null && this.cf.isDone();
        }

        @Override
        public void run() {
            if (this.cf != null &&(!this.cf.isDone() || !this.cf.isConnected())) {
                if (this.cf.isConnected()) {
                    ReconnectManager.this.tasks.remove(this.reconnectKey);
                    throw new RuntimeException("连接成功");
                }
            } else {
                this.cf = Remoting.clientMgr().getAsync(this.appName,this.targetUrl,
                        this.listeners,null);
            }
        }
    }

}
